Skip to content

feat(features): support scoped 'features disable' - #246

Merged
LauJosefsen merged 2 commits into
mainfrom
lejo/features-disable-scoped
Jul 13, 2026
Merged

feat(features): support scoped 'features disable'#246
LauJosefsen merged 2 commits into
mainfrom
lejo/features-disable-scoped

Conversation

@LauJosefsen

Copy link
Copy Markdown
Collaborator

Summary

Adds --project, --gitlab-group, --github-org, and --exclude flags to gitte features disable, mirroring the flags already on gitte features enable.

Previously disable could only turn a gate off entirely. A scoped disable now removes only the matching projects from the gate's current scope, leaving it enabled for the rest — and disables the gate entirely once the last project is removed. This makes per-project enable/disable symmetric:

gitte features enable dev-build --project frontend-spilnu    # on for one project
gitte features disable dev-build --project frontend-spilnu   # off for just that one

Changes

  • cmd/features.go: disable gains the scope flags; no flags = disable entirely (unchanged behaviour). Extracted buildOverrideFromFlags (shared with enable).
  • features/scope.go: new exported ProjectsInGateScope(cfg, gate) to resolve the set of projects a gate's configured scope applies to (reuses existing scope helpers to recompute the override after removal).
  • docs/commands.md, docs/config.md: document scoped disable.
  • features/scope_test.go: tests for ProjectsInGateScope.

Behaviour

Verified against a fixture workspace:

Action Result
disable <gate> --project X on a full-scope gate gate scoped to the remaining projects (X excluded)
disable <gate> --project <last> gate removed entirely
disable <gate> --project X when gate off "was not enabled"
disable <gate> --project <unknown/out-of-scope> "was not enabled for the given project(s)", state unchanged

go build ./..., go vet ./..., and go test ./... all pass.

Add --project/--gitlab-group/--github-org/--exclude flags to 'gitte features
disable', mirroring 'enable'. A scoped disable removes only the matching projects
from a gate's current scope, leaving it enabled for the rest, and disables the gate
entirely once the last project is removed.

Extract buildOverrideFromFlags (shared with enable) and add
features.ProjectsInGateScope to resolve a gate's configured project set.

@jakobkollerup jakobkollerup left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice feature — clean refactor of the flag parsing, good docs, and the symmetric enable/disable UX makes sense. I left inline comments; the one on CheckedStateToOverride is the one I'd hold merge on, since a scoped disable can quietly broaden the gate's effective scope (confirmed with a repro test).

Two things that don't fit an inline anchor:

  • features/tui.go enterScopeTree now duplicates ProjectsInGateScope verbatim — it could call the new helper.
  • Minor behavior change: a state entry with Enabled: false (hand-edited state file) now prints "was not enabled" and is left in place, where the old code deleted it. Harmless, just noting it.

Comment thread cmd/features.go
Comment thread cmd/features.go Outdated
Comment thread cmd/features.go Outdated
Comment thread cmd/features.go
Comment thread features/scope_test.go
Address review on scoped 'features disable':
- runtime: intersect OverrideScope with the gate's config scope in
  extraEnvForProject so an override can only narrow, never broaden, the
  effective scope (also fixes the pre-existing TUI scope-editor flaw).
- disable: unscoped path now cleans up a state entry for a gate removed
  from config instead of erroring; scoped path still requires config.
- enable/disable: error when --exclude is given without --gitlab-group/--github-org.
- tui: enterScopeTree reuses features.ProjectsInGateScope.
- test: regression test that an override cannot broaden the config scope.
@LauJosefsen
LauJosefsen force-pushed the lejo/features-disable-scoped branch from 0ea0a6e to 5651f05 Compare July 13, 2026 09:37
@LauJosefsen

Copy link
Copy Markdown
Collaborator Author

Thanks @jakobkollerup — all addressed in the latest push.

  • Scope broadening (the merge-blocker): fixed at the source you pointed to — extraEnvForProject now requires the gate's config scope to match in addition to the override, so an OverrideScope can only ever narrow, never broaden (this also neutralises the pre-existing TUI scope-editor variant). Added TestExtraEnvForProject_OverrideCannotBroadenConfigScope, built directly on your repro (other must get no env after disable --project svc-a) — it fails on the old code and passes now.
  • Gate removed from config couldn't be disabled: the unscoped path now consults state only and cleans up a stale entry regardless of config presence (and regardless of a hand-edited Enabled: false). The scoped path still requires config, since it needs the configured scope to reconstruct the override.
  • --exclude without group/org: now errors (--exclude requires --gitlab-group or --github-org) on both enable and disable.
  • fs, enabled := naming: renamed to fs, ok :=.
  • enterScopeTree duplication: now calls the shared features.ProjectsInGateScope.

go build/vet/test pass; also re-verified the disable flows against a fixture workspace.

@LauJosefsen
LauJosefsen merged commit 453f7bd into main Jul 13, 2026
12 checks passed
@LauJosefsen
LauJosefsen deleted the lejo/features-disable-scoped branch July 13, 2026 10:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants